-----------------------------------------------------------------------------
--
-- Module      :  ParseUtils
-- Copyright   :  (c) Lakshmi Narasimhan
-- License     :  GNU-GPL
--
-- Maintainer  :  <lakshminaras2002 at gmail dot com>
-- Stability   :  provisional
-- Portability :  portable
--
--
--
---------------------------------------------------------------------------------
module ParseUtils(run,expr) where

import Text.ParserCombinators.Parsec
--parser module to extract numbers with . and exponents, exponents
-- can only be integers
-- Number = (N) | digits ( (.) | (.)digitsE (+-)) digits
--
number = do {
         dnum <- try (doublenumber)
         ; return dnum
	 }
         <|>
         do {
         inum <- try integernumber
         ; return inum
         }
         <?> "number"


doublenumber  :: Parser String
doublenumber  = do{
	     prefix<- many1 digit
	     ;dotNumber <- dotExpr
	     ;expoSuffix <- exponentExpr
	     ;return ((prefix ++ dotNumber ++ expoSuffix))
	    }
        <?> "double number"

integernumber = do{
             prefix<- many1 digit
             ;return (prefix)
           }
        <?> "integer number"

dotExpr :: Parser String
dotExpr = do{
	    char '.'
	    ;suffix <- many1 digit
	    ;return (('.':[])++suffix)
	   }
	<|>  return []


exponentExpr :: Parser String
exponentExpr = do{
	    char 'e'
 	    ;plusMinus <- oneOf "+-"
	    ;suffix <- many1 digit
	    ;return (('e':plusMinus:[])++suffix)
	   }
	<|>  return []

-- rewrite with left factoring and use Syntax directed translation to postfix
--expr = factor expr'
--expr' = (+-) expr | E
--factor = (term|(unary)) factor'
--factor' = (*/) factor | (^) factor | E
--term = Number |(expr)
--unary = log term|ln term|e term 

expr :: Parser [String]
expr = do{
	a<- try(factor)
        ;b<- expr'
        ;return ((a)++(b))
	}

expr' :: Parser [String]
expr' = do{
          op <- try(oneOf "+-")
          ;b <- expr
          ;return (b++((op:[]):[])) --oneOf returns a char,
                                    --this is one way of converting a char to a [String] by sticking
                                    --two  [] data constructors at the end
          }
         <|> return []

factor :: Parser [String]
factor = do{
	  a <- try(term)
	  ;b <- factor'
          ;return ((a) ++ (b))
	  }
          <|>
         do{
          a <- unary
          ;b<-factor'
          ;return(a++b)
         }

factor' :: Parser [String]
factor' = do{
	      op <- try (oneOf "*/")
	      ;val <- factor
          ;return ((val)++ ((op:[]):[]))
          }
          <|>
          do {
          op <- try (oneOf "^%")
          ; val <- factor
          ; return ((takeWhile ((/=) ".") val) ++ ((op:[]):[]) )
          }
          <|> return []

term :: Parser [String]
term =  do{
	leftbrace <- try (oneOf "(")
        ;a <- expr
        ;rightbrace <- char ')'
	;return a
        }
	<|>
	do{	
         num <- number
         ;return (num:[])
         }

unary :: Parser [String]
unary = do{
          a<-try(string "log")
          ;b<-term 
          ;return (b++[a])
         }
         <|> 
         do{
          a<-string "ln"
          ;b<-term
          ;return (b++[a])
         }
         <|>
         do{
          a<-string "euler"
          ;b<-term
          ;return (b++[a])
          ;
         }
         <|>
         do{
          a<-char '-'
          ;b<-term
          ;return (b++["$"])
          ;
         }
        
run :: Parser [String] -> String -> IO (Either String [String])
run p input
        = case (parse p "expression" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          ; return (Left (show err))
                          }
            Right x  -> do{
            ;return (Right x)
			  }
